package la.iok.hzsvn.lewin.movie.service;

import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.entity.ClueCard;
import la.iok.hzsvn.lewin.movie.entity.ClueCardGroup;
import la.iok.hzsvn.lewin.movie.mapper.ClueCardMapper;
import la.iok.hzsvn.lewin.movie.model.*;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.NotNullElement;
import la.iok.hzsvn.share.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ClueCardServiceImpl extends BaseServiceImpl<ClueCard,ClueCardMapper,Long> implements ClueCardService {
    private final ClueCardGroupService clueCardGroupService;
    private final MovieService movieService;
    private final ClueCardFileService clueCardFileService;

    public ClueCardServiceImpl(ClueCardMapper mapper, ClueCardGroupService clueCardGroupService,
                               MovieService movieService,
                               ClueCardFileService clueCardFileService) {
        super(mapper);
        this.clueCardGroupService = clueCardGroupService;
        this.movieService = movieService;
        this.clueCardFileService = clueCardFileService;
    }

    @NotNull
    @Override
    public Long save(@NotNull Token token, @NotNull Long groupId, @NotNull ClueCardParam param) {
        String name = ErrorCode.NAME_BLANK_ERROR.assertNotBlank(param.getName());
        ErrorCode.CLUE_CARD_TYPE_ERROR.assertTrue(param.validType(),param.getType());
        ClueCardGroup group = clueCardGroupService.select(groupId);
        ErrorCode.CLUE_GROUP_NOT_EXIST.assertNotNull(group,groupId);
        movieService.validate(token,group.getMovieId());

        ClueCard entity = new ClueCard();
        entity.setName(name);
        entity.setType(param.getType());
        entity.setGroupId(groupId);
        insertSelective(entity);
        return entity.getId();
    }

    @Override
    public void update(@NotNull Token token, @NotNull Long id, @NotNull ClueCardParam param) {
        String name = ErrorCode.NAME_BLANK_ERROR.assertNotBlank(param.getName());
        ErrorCode.CLUE_CARD_TYPE_ERROR.assertTrue(param.validType(),param.getType());
        validate(token, id);
        ClueCard entity;

        entity = new ClueCard();
        entity.setName(name);
        entity.setType(param.getType());
        entity.setId(id);
        mapper.updateSelective(entity);
    }

    @NotNull
    private ClueCard validate(@NotNull Token token, @NotNull Long id) {
        ClueCard entity = select(id);
        ErrorCode.CLUE_CARD_NOT_EXIST.assertNotNull(entity, id);
        ClueCardGroup group = clueCardGroupService.select(entity.getGroupId());
        ErrorCode.CLUE_GROUP_NOT_EXIST.assertNotNull(group,entity.getGroupId());
        movieService.validate(token,group.getMovieId());
        return entity;
    }

    @Transactional
    @Override
    public void uploadHdFile(@NotNull Token token, @NotNull Long id, @NotNull String path, @NotNull MultipartFile file) {
        path = ErrorCode.STORE_PATH_EMPTY_ERROR.assertNotBlank(path);
        ClueCard entity = validate(token,id);
        Long fileId = clueCardFileService.uploadFile(file);
        clueCardFileService.decrement(entity.getHdFileId());
        update(id,"hdFileId",fileId);
        update(id,"hdFile",path);
        clueCardFileService.increment(fileId);
    }

    @Override
    public ObsSignedUrl uploadHdFile(@NotNull Token token, @NotNull Long id, @NotNull DigestInfo digest) {
        String path = ErrorCode.STORE_PATH_EMPTY_ERROR.assertNotBlank(digest.getPath());
        ClueCard entity = validate(token,id);
        ObsSignedUrl url = clueCardFileService.uploadFile(digest);
        clueCardFileService.decrement(entity.getHdFileId());
        update(id,"hdFileId",url.getFileId());
        update(id,"hdFile",path);
        clueCardFileService.increment(url.getFileId());
        url.setFileId(null);
        return url;
    }

    @Transactional
    @Override
    public void uploadSdFile(Token token, Long id, String path, MultipartFile file) {
        path = ErrorCode.STORE_PATH_EMPTY_ERROR.assertNotBlank(path);
        ClueCard entity = validate(token,id);
        Long fileId = clueCardFileService.uploadFile(file);
        clueCardFileService.decrement(entity.getSdFileId());
        update(id,"sdFileId",fileId);
        update(id,"sdFile",path);
        clueCardFileService.increment(fileId);
    }

    @Override
    public ObsSignedUrl uploadSdFile(@NotNull Token token, @NotNull Long id, @NotNull DigestInfo digest) {
        String path = ErrorCode.STORE_PATH_EMPTY_ERROR.assertNotBlank(digest.getPath());
        ClueCard entity = validate(token,id);
        ObsSignedUrl url = clueCardFileService.uploadFile(digest);
        clueCardFileService.decrement(entity.getSdFileId());
        update(id,"sdFileId",url.getFileId());
        update(id,"sdFile",path);
        clueCardFileService.increment(url.getFileId());
        url.setFileId(null);
        return url;
    }

    @Transactional
    @Override
    public void delete(@NotNull Token token, @NotNull Long id) {
        ClueCard entity = validate(token,id);
        clueCardFileService.decrement(entity.getSdFileId());
        clueCardFileService.decrement(entity.getHdFileId());
        delete(id);
    }

    @Override
    public List<ClueCardVo> movieClueCards(@NotNull Token token, @NotNull Long movieId) {
        movieService.validate(token,movieId);
        List<ClueCardGroupVo> vos = clueCardGroupService.clueCardGroups(token,movieId);
        Set<Long> groupIds = vos.stream().map(ClueCardGroupVo::getId).collect(Collectors.toSet());
        List<ClueCard> list = clueCards(groupIds);
        return list.stream().map(this::po2vo).collect(Collectors.toList());
    }

    @Override
    public List<ClueCard> clueCards(@NotNull @NotNullElement Set<Long> groupIds) {
        if(groupIds.isEmpty()){
            return Collections.emptyList();
        }
        return mapper.listInProperty("groupId",groupIds);
    }

    @Override
    public String sdFileDigest(@Nullable Long id) {
        ClueCard entity = select(id);
        ErrorCode.CLUE_CARD_NOT_EXIST.assertNotNull(entity,id);
        return clueCardFileService.digest(entity.getSdFileId());
    }

    @Override
    public String sdFileStorePath(@Nullable Long id) {
        ClueCard entity = select(id);
        ErrorCode.CLUE_CARD_NOT_EXIST.assertNotNull(entity,id);
        return clueCardFileService.storePath(entity.getSdFileId());
    }

    @Override
    public String hdFileDigest(@Nullable Long id) {
        ClueCard entity = select(id);
        ErrorCode.CLUE_CARD_NOT_EXIST.assertNotNull(entity,id);
        return clueCardFileService.digest(entity.getHdFileId());
    }

    @Override
    public String hdFileStorePath(@Nullable Long id) {
        ClueCard entity = select(id);
        ErrorCode.CLUE_CARD_NOT_EXIST.assertNotNull(entity,id);
        return clueCardFileService.storePath(entity.getHdFileId());
    }

    @Override
    public void downloadSdFile(@NotNull Token token, @NotNull HttpServletResponse response, @NotNull Long id) {
        ClueCard entity = validate(token,id);
        clueCardFileService.downloadFile(response,entity.getSdFileId(),entity.getName());

    }

    @Override
    public void downloadHdFile(@NotNull Token token, @NotNull HttpServletResponse response, @NotNull Long id) {
        ClueCard entity = validate(token,id);
        clueCardFileService.downloadFile(response,entity.getHdFileId(),entity.getName());
    }

    @Override
    public void deleteGroup(Token token, Long groupId) {
        List<ClueCard> list = listByProperty("groupId",groupId);
        ErrorCode.PROPERTY_CHECK_ERROR.assertEmpty(list,"线索","请先删除线索分组中所有线索之后再试");
        clueCardGroupService.delete(token,groupId);
    }

    @NotNull
    private ClueCardVo po2vo(@NotNull ClueCard po){
        ClueCardVo vo = new ClueCardVo();
        BeanUtils.copyProperties(po,vo);
        vo.setGroup(po.getGroupId());
        return vo;
    }

}
